#include <iostream>
#include <memory>
#include <new> // for placement new

class Base {
public:
    Base() { std::cout << "Base constructor\n"; }
    virtual ~Base() { std::cout << "Base destructor\n"; }
};

class Derived : public Base {
public:
    Derived() { std::cout << "Derived constructor\n"; }
    ~Derived() override { std::cout << "Derived destructor\n"; }
};

// 全局对象，用于展示全局和静态对象析构调用
Base globalBase;


void functionWithLocalObject() {
    std::cout << "Entering functionWithLocalObject\n";
    Derived localDerived;
    std::cout << "Exiting functionWithLocalObject\n";
}

void functionWithDynamicObject() {
    std::cout << "Entering functionWithDynamicObject\n";
    Base* dynamicBase = new Derived;
    delete dynamicBase; // 触发析构
    std::cout << "Exiting functionWithDynamicObject\n";
}

void functionWithSmartPointer() {
    std::cout << "Entering functionWithSmartPointer\n";
    std::unique_ptr<Base> smartPtr = std::make_unique<Derived>();
    std::cout << "Exiting functionWithSmartPointer\n";
}

// 用于placement new的缓冲区
// alignas确保buffer的对齐方式满足Derived对象的对齐要求
alignas(Derived) char buffer[sizeof(Derived)];

void functionWithPlacementNew() {
    std::cout << "Entering functionWithPlacementNew\n";
    
    // 在预分配的buffer上使用placement new构造Derived对象
    // 使用placement new意味着我们使用现有的内存而不是新分配内存
    Derived* placementObj = new (buffer) Derived;
    
    // 显式调用析构函数进行对象的清理
    // 必须手动调用析构函数，因为placement new不涉及自动析构调用
    placementObj->~Derived();


    // 由于内存是由buffer提供的，不是由new分配的，因此不需要也不能使用delete
    // 使用delete会尝试释放placement new使用的内存，这会导致未定义行为
    // buffer在离开作用域时，作为局部变量自动释放，无需手动管理内存释放

    std::cout << "Exiting functionWithPlacementNew\n";
}

int main() {
    functionWithLocalObject();
    functionWithDynamicObject();
    functionWithSmartPointer();
    functionWithPlacementNew();

    std::cout << "Exiting main function\n";
    // 全局对象和静态对象的析构函数将在main函数退出后调用
    return 0;
}

// 这里仅为了演示析构函数的调用，并且在实际代码中应避免这样做。